package com.enlorenz.core.annotation.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.enlorenz.common.util.DataDetUtils;
import com.enlorenz.common.util.ReflectionUtils;
import com.enlorenz.common.util.ReflectionUtils.IFieldsIteratorCallback;
import com.enlorenz.core.annotation.Parameter;
import com.enlorenz.core.annotation.PropEntity;
import com.enlorenz.core.annotation.Property;
import com.enlorenz.core.annotation.base.AnnoBaseWrapper;
import com.enlorenz.core.annotation.base.AnnoMethodWrapper;
import com.enlorenz.core.annotation.base.AnnoParamPropertyWrapper;
import com.enlorenz.core.annotation.base.AnnoParamWrapper;
import com.enlorenz.core.annotation.base.AnnoServiceWrapper;
import com.enlorenz.core.annotation.base.InOut;

/**
 * 注释工具
 * @author lcb
 */
public class AnnotationUtils {
	

	/**
	 * 获取类的属性注释Map,属性名为key
	 * @param claxx 类
	 * @return 属性注释Map
	 */
	public static Map<String,PropEntity> getClassMap(Class<?> claxx){
		Map<String,PropEntity> propMap=new HashMap<String, PropEntity>();
		List<PropEntity> propList=AnnotationUtils.
				getPropEntityList(claxx);
		if(DataDetUtils.isCollectionEmpty(propList)){
			return propMap;
		}
		for(PropEntity ep:propList){
			propMap.put(ep.getFieldName(), ep);
		}
		return propMap;
	}
	
	/**
	 * 获取类的属性名列表
	 * @param claxx 类对象
	 * @return 属性名列表
	 */
	public static List<PropEntity> getPropEntityList(Class<?> claxx){
		final List<PropEntity> list=new ArrayList<PropEntity>();
		ReflectionUtils.iterateClassFields(claxx, new IFieldsIteratorCallback() {
			@Override
			public void callback(Object object, Class curClass, Field field)
					throws Exception {
				Property prop=field.getAnnotation(Property.class);
				if(null == prop){
					return;
				}
				PropEntity ep=new PropEntity(field.getName(),prop);
				list.add(ep);
			}
		});
		
		return list;
	}
	
	/**
	 * 获取类的属性名列表
	 * @param claxx 类对象
	 * @param annoClass 注释类对象
	 * @param readNull 是否读取不存在注解的域
	 * @return 属性名列表
	 */
	@SuppressWarnings("rawtypes")
	public static <T> List<PropAnnoWrapper<T>>  getAnnoList(Class claxx,final Class annoClass){
		return getAnnoList(claxx, annoClass, true);
	}
	
	/**
	 * 获取类的属性名列表
	 * @param claxx 类对象
	 * @param annoClass 注释类对象
	 * @return 属性名列表
	 */
	@SuppressWarnings("rawtypes")
	public static <T> List<PropAnnoWrapper<T>>  getAnnoList(Class claxx,final Class annoClass,final boolean readNull){
		final List<PropAnnoWrapper<T>> list=new ArrayList<PropAnnoWrapper<T>>();
		ReflectionUtils.iterateClassFields(claxx, new IFieldsIteratorCallback() {
			@Override
			public void callback(Object object, Class curClass, Field field)
					throws Exception {
				T prop=(T)field.getAnnotation(annoClass);
				if(!readNull){
					if(null == prop){
						return;
					}
				}
				
				PropAnnoWrapper paw=new PropAnnoWrapper();
				paw.setFieldName(field.getName());
				paw.setAnnoObject(prop);
				list.add(paw);
			}
		});
		return list;
	}
	
	/**
	 * 获取类的属性名Map
	 * @param claxx 类对象
	 * @param annoClass 注释类对象
	 * @return 属性名列表
	 */
	@SuppressWarnings("rawtypes")
	public static <T> Map<String,PropAnnoWrapper<T>> getAnnoMap(Class claxx,final Class annoClass){
		List<PropAnnoWrapper<T>> pList=getAnnoList(claxx, annoClass);
		if(DataDetUtils.isCollectionEmpty(pList)){
			return null;
		}
		
		Map<String,PropAnnoWrapper<T>> map=new 
				LinkedHashMap<String, PropAnnoWrapper<T>>(pList.size());
		for(PropAnnoWrapper<T> p:pList){
			map.put(p.getFieldName(), p);
		}
		return map;
	}
	
	/**
	 * 属性注释封装类
	 * @author Karma
	 */
	public static class PropAnnoWrapper<T>{
		private String fieldName;
		private T annoObject;
		public String getFieldName() {
			return fieldName;
		}
		public void setFieldName(String fieldName) {
			this.fieldName = fieldName;
		}
		public T getAnnoObject() {
			return annoObject;
		}
		public void setAnnoObject(T annoObject) {
			this.annoObject = annoObject;
		}
	}
	
	
	public static void main(String[] args) {
		System.out.println(getAnnoList(InOut.class,Property.class));
	}
	
	
	/**
	 * 在Class中获取服务名
	 * 服务名为类注释的name属性
	 * @param claxx 传入class
	 * @return 服务名
	 */
	public static String findServiceName(Class claxx){
		//填充注释属性
		Property property=(Property)claxx.getAnnotation(Property.class);
		if(null == property){
			return null;
		}
		return property.name();
	}
	
	/**
	 * 注释遍历回调
	 * @author lcb
	 */
	public static interface IAnnoIteratorHook{
		
		/**
		 * 类注释
		 * @param claxx 类对象
		 * @param property 注释
		 */
		void classAnno(Class claxx,Property property);
		
		/**
		 * 方法注释回调
		 * @param method 方法名
		 * @param property 注释
		 */
		void methodAnno(Method method,Property property);
		
		/**
		 * 方法参数注释回调
		 * @param method 方法名
		 * @param type 参数类型
		 * @param propClass 注释
		 */
		void methodParamAnno(Method method,Class type,Parameter propClass);
		
		/**
		 * 返回参数注释
		 * @param type 返回类型
		 * @param propClass 注释
		 */
		void returnAnno(Class type,Parameter propClass);
	}
	
	/**
	 * 遍历类对象方法的注释
	 * @param claxx 输入类对象
	 * @param annoIteratorHook 遍历回调函数
	 */
	public static void iterateClassMethodAnno(Class claxx,IAnnoIteratorHook annoIteratorHook){
		//填充注释属性
		Property property=(Property)claxx.getAnnotation(Property.class);
		annoIteratorHook.classAnno(claxx, property);
		
		Method [] methodArr=claxx.getMethods();
		if(DataDetUtils.isArrEmpty(methodArr)){
			return;
		}
		
		for(Method method:methodArr){
			//填充注释属性
			Property methodProperty=method.getAnnotation(Property.class);
			if(null == methodProperty){
				continue;
			}
			
			annoIteratorHook.methodAnno(method, methodProperty);
			
			//获取参数类都系数组
			Class [] paramClassArr=method.getParameterTypes();
			if(!DataDetUtils.isArrEmpty(paramClassArr)){
				Annotation[][] annArr=method.getParameterAnnotations();
				for(int i=0;i<paramClassArr.length;i++){
					Class paramClass=paramClassArr[i];
					Annotation [] pAnno=annArr[i];
					Parameter parameter=findPropClassFromAnnoArr(pAnno);
					annoIteratorHook.methodParamAnno(method,paramClass,parameter);
				}
			}
			
			
			//获取返回对象
			Class returnClass=method.getReturnType();
			if(null!=returnClass){
				//查看是否有返回值的实现类注释
				Parameter parameter=method.getAnnotation(Parameter.class);
				Class dstClass=returnClass;
				annoIteratorHook.returnAnno(returnClass, parameter);
			}
		}
	}
	
	/**
	 * 从类对象中获取注释服务对象
	 * @param claxx 输入的类对象
	 * @return 注释服务对象
	 */
	public static AnnoServiceWrapper getAnnoServiceWrapper(Class claxx){
		//服务注释包装类
		final AnnoServiceWrapper service=new AnnoServiceWrapper();
		service.setAnnoPropName(claxx.getSimpleName());
		
		final AnnoMethodWrapper [] curMethodWrapper=new AnnoMethodWrapper[1];
		
		iterateClassMethodAnno(claxx, new IAnnoIteratorHook() {
			@Override
			public void classAnno(Class claxx, Property property) {
				fillAnnoBaseWrapper(service, property);
			}
			
			@Override
			public void methodAnno(Method method, Property property) {
				//创建方法注释包装类
				AnnoMethodWrapper methodWrapper=new AnnoMethodWrapper();
				curMethodWrapper[0]=methodWrapper;
				
				methodWrapper.setAnnoPropName(method.getName());
				service.addAnnoMethodWrapper(methodWrapper);
				fillAnnoBaseWrapper(methodWrapper, property);
			}
			
			@Override
			public void methodParamAnno(Method method, Class type, Parameter parameter) {

				//检查是否有实现类的注释，如果有则用此类对象
				Class dstClass=type;
				if(null!=parameter){
					Class pClass=getParameterClass(parameter);
					if(null!=pClass){
						dstClass=pClass;
					}
				}
				
				AnnoParamWrapper paramWrapper=getAnnoParamWrapper(dstClass);
				paramWrapper.setAnnoPropName(dstClass.getSimpleName());
				paramWrapper.setImplClass(dstClass.getName());
				curMethodWrapper[0].addAnnoParamWrapper(paramWrapper);
				
				//Property paramProp=(Property)dstClass.getAnnotation(Property.class);
				fillAnnoBaseWrapper(paramWrapper, parameter);
				
			}
			
			@Override
			public void returnAnno(Class type, Parameter parameter) {
				Class dstClass=type;
				if(null!=parameter){
					Class pClass=getParameterClass(parameter);
					if(null!=pClass){
						dstClass=pClass;
					}
				}
				
				AnnoParamWrapper paramWrapper=getAnnoParamWrapper(dstClass);
				paramWrapper.setAnnoPropName(dstClass.getSimpleName());
				paramWrapper.setImplClass(dstClass.getName());
				curMethodWrapper[0].setReturnParam(paramWrapper);
				
				//Property paramProp=(Property)dstClass.getAnnotation(Property.class);
				fillAnnoBaseWrapper(paramWrapper, parameter);
			}
			
		});
		return service;
	}
	
	/**
	 * 获取参数注解的Class属性
	 * @param parameter 参数注解
	 * @return Class属性
	 */
	public static Class getParameterClass(Parameter parameter){
		Class pClass=parameter.impl();
		if(pClass.getName().equals(Parameter.class.getName())){
			return null;
		}
		return pClass;
	}
	
	/**
	 * 从参数类对象中获取参数包装类
	 * @param paramClass 参数类对象
	 * @return 参数包装类
	 */
	public static AnnoParamWrapper getAnnoParamWrapper(Class paramClass){
		final AnnoParamWrapper paramWrapper=new AnnoParamWrapper();
		Property paramProp=(Property)paramClass.getAnnotation(Property.class);
		fillAnnoBaseWrapper(paramWrapper, paramProp);
		
		ReflectionUtils.iterateFields(paramClass, null, true, new IFieldsIteratorCallback(){
			@Override
			public void callback(Object object, Class curClass,
					Field field) throws Exception {
				Property property=field.getAnnotation(Property.class);
				if(null == property){
					return;
				}
				AnnoParamPropertyWrapper paramProperty=new AnnoParamPropertyWrapper();
				paramProperty.setAnnoPropName(field.getName());
				fillAnnoBaseWrapper(paramProperty, property);
				paramWrapper.addAnnoParamPropertyWrapper(paramProperty);
				
				Class implClass=property.impl();
				if(null!=implClass){
					getAnnoParamWrapper(paramWrapper,field.getName(),implClass);
				}
				
			}
		});
		return paramWrapper;
	}
	
	public static void getAnnoParamWrapper(final AnnoParamWrapper paramWrapper,final String parentParamName,Class parentClass){
		ReflectionUtils.iterateFields(parentClass, null, true, new IFieldsIteratorCallback(){
			@Override
			public void callback(Object object, Class curClass,
					Field field) throws Exception {
				Property property=field.getAnnotation(Property.class);
				if(null == property){
					return;
				}
				AnnoParamPropertyWrapper paramProperty=new AnnoParamPropertyWrapper();
				String curProp=parentParamName+"."+field.getName();
				paramProperty.setAnnoPropName(curProp);
				fillAnnoBaseWrapper(paramProperty, property);
				paramWrapper.addAnnoParamPropertyWrapper(paramProperty);
				
				Class implClass=property.impl();
				if(null!=implClass){
					getAnnoParamWrapper(paramWrapper,curProp,implClass);
				}
				
			}
		});
	}
	
	
	/**
	 * 将property属性填充到注释包装类中
	 * @param annoBaseWrapper 基础注释包装类
	 * @param property 注释
	 */
	public static void fillAnnoBaseWrapper(AnnoBaseWrapper annoBaseWrapper,Property property){
		if(null == property){
			return;
		}
		annoBaseWrapper.setAnnoName(property.name());
		annoBaseWrapper.setAnnoDesp(property.desc());
	}
	
	/**
	 * 将parameter属性填充到注释包装类中
	 * @param annoBaseWrapper 基础注释包装类
	 * @param parameter 注释
	 */
	public static void fillAnnoBaseWrapper(AnnoBaseWrapper annoBaseWrapper,Parameter parameter){
		if(null == parameter){
			return;
		}
		annoBaseWrapper.setAnnoName(parameter.name());
		annoBaseWrapper.setAnnoDesp(parameter.descp());
	}
	
	/**
	 * 在数组中查找PropClass注释
	 * @param annoArr
	 * @return
	 */
	public static Parameter findPropClassFromAnnoArr(Annotation [] annoArr){
		if(DataDetUtils.isArrEmpty(annoArr)){
			return null;
		}
		
		for(Annotation anno:annoArr){
			if(anno instanceof Parameter){
				return (Parameter)anno;
			}
		}
		return null;
	}
	
	/**
	 * 在数组中查找property注释
	 * @param annoArr
	 * @return
	 */
	public static Property findPropertyFromAnnoArr(Annotation [] annoArr){
		if(DataDetUtils.isArrEmpty(annoArr)){
			return null;
		}
		
		for(Annotation anno:annoArr){
			if(anno instanceof Property){
				return (Property)anno;
			}
		}
		return null;
	}
	
	
}
